package com.gosophia.commons;

//TODO: 单列多条件查询
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.util.Assert;

/**
 * 机 能： 检索条件类 ，需要比较值的有（gt,ge,eq,lt,le,btween,ne）
 * 
 * @author 任学会
 * 
 * @since 2010-05-25 Copyright (c) 2010 Gosophia corporation All Rights
 *        Reserved.
 */
public class PropertyFilter implements Serializable {

 
    private static final long serialVersionUID = 1L;

    /**
     * 过滤条件Id
     */
    private Long propertyFilterId;
    
    /**
     * 条件属性名称
     */
    private String propertyName;

    /**
     * 条件属性值
     */
    private Object propertyValue;
    
    private String propertyValueStr;
    
    /**
     * 条件属性值2
     * 注：between条件时用到
     */
    private Object propertyValue1;
    
    private String propertyValue1Str;
    
    /**
     * 属性值的类型
     */
    private ParamValueType propertyValueTypeEnum = ParamValueType.STRING;
    
    /**
     * 属性值的类型-字符串类型，作用在于枚举类型以字符串类型保存到数据库中
     */
    private String  propertyValueType = ParamValueType.STRING.toString();
    
    /**
     * 操作符（比较操作符）
     */
    private OperatorType operator;
    
    /**
     * 操作符-字符串类型，作用在于枚举类型以字符串类型保存到数据库中
     */
    private String operatorString;
    
    /**
     * 数据格式，日期等需要格式化的数据类型使用
     */
    private String toCharFormat = "";
    
	/**
     * or过滤条件
     */
    private List<PropertyFilter> orFilters;
    
    /**
     * and 过滤条件
     */
    private List<PropertyFilter> andFilters;
    
    public String getToCharFormat() {
		return toCharFormat;
	}

	public void setToCharFormat(String toCharFormat) {
		this.toCharFormat = toCharFormat;
	}

	public List<PropertyFilter> getAndFilters() {
    	if (this.andFilters == null){
    		this.andFilters = new ArrayList<PropertyFilter>();
    	}
		return andFilters;
	}
    
    @SuppressWarnings("unused")
	private void setAndFilters(List<PropertyFilter> andFilters) {
		this.andFilters = andFilters;
	}
    
    @SuppressWarnings("unused")
    private void setPropertyFilterId(Long propertyFilterId) {
        this.propertyFilterId = propertyFilterId;
    }

    public Long getPropertyFilterId() {
        return propertyFilterId;
    }
    
    public String getPropertyName() {
        return propertyName;
    }

    public void setPropertyName(String propertyName) {
        this.propertyName = propertyName;
    }
    
    public Object getPropertyValue(){
        
        if (propertyValueStr != null
        		&& propertyValue instanceof String 
                && !this.getPropertyValueTypeEnum().equals(ParamValueType.STRING)){

            String s = propertyValueStr;
            
            switch (this.getPropertyValueTypeEnum()){
            
            case BOOLEAN:
                propertyValue = Boolean.parseBoolean(s);
                break;
            case INTEGER:
                propertyValue = Integer.parseInt(s);
                break;
            case LONG:
                propertyValue = Long.parseLong(s);
                break;
            case DOUBLE:
                propertyValue = Double.parseDouble(s);
                break;
            case DATE:
            	if(getToCharFormat().endsWith("yyyy-MM-dd hh24:mi:ss")) {
            		propertyValue = DateTranslate.simpleStringToDateTime(s, "yyyy-MM-dd HH:mm:ss");	
            	} else {
            	   propertyValue = DateTranslate.simpleStringToDateTime(s, getToCharFormat());	
            	}
                
                break;
            default:
                break;
            }
        } else if (propertyValue instanceof String){
        	propertyValue = propertyValue.toString().trim();
        }
        
        return propertyValue;
    }
    
    public void setPropertyValue(Object propertyValue) {
        this.propertyValue = propertyValue;
        if (propertyValue instanceof Date){
            this.propertyValueStr = DateTranslate.simpleDateTimeToString((Date) propertyValue);
        }else{
            this.propertyValueStr = this.propertyValue.toString();
        }

        setPropertyValueTypeEnum(
        		ParamValueType.valueOf(ParamValueType.class, propertyValue.getClass().getSimpleName().toUpperCase()));
        setPropertyValueType(propertyValue.getClass().getSimpleName().toUpperCase());
    }
    
    @SuppressWarnings("unused")
    private String getPropertyValueStr() {
        return propertyValueStr;
    }
    
    public void setPropertyValueStr(String propertyValueStr) {
        this.propertyValueStr = propertyValueStr;
        if (this.propertyValueTypeEnum == null){
        	this.propertyValueTypeEnum = ParamValueType.STRING;
        }
        this.propertyValue = this.propertyValueStr;
    }

    public Object getPropertyValue1() {
        if (propertyValue1Str != null
        		&& propertyValue1 instanceof String
                && !this.getPropertyValueTypeEnum().equals(ParamValueType.STRING)){

            String s = propertyValue1Str;
            
            switch (this.getPropertyValueTypeEnum()){
            
            case BOOLEAN:
                propertyValue1 = Boolean.parseBoolean(s);
                break;
            case INTEGER:
                propertyValue1 = Integer.parseInt(s);
                break;
            case LONG:
                propertyValue1 = Long.parseLong(s);
                break;
            case DOUBLE:
                propertyValue1 = Double.parseDouble(s);
                break;
            case DATE:
                propertyValue1 = DateTranslate.simpleStringToDateTime(s, getToCharFormat());
                break;
            default:
                break;
            }
        }else if (propertyValue1 instanceof String){
        	propertyValue1 = propertyValue1.toString().trim();
        }
        
        return propertyValue1;
    }

    public void setPropertyValue1(Object propertyValue1) {
        this.propertyValue1 = propertyValue1;
        if (propertyValue1 instanceof Date){
            this.propertyValue1Str = DateTranslate.simpleDateTimeToString((Date) propertyValue);
        }else{
            this.propertyValue1Str = this.propertyValue.toString();
        }
    }
    
    @SuppressWarnings("unused")
    private String getPropertyValue1Str() {
        return propertyValue1Str;
    }
    
    public void setPropertyValue1Str(String propertyValue1Str) {
        this.propertyValue1Str = propertyValue1Str;
        if (this.propertyValueTypeEnum == null){
        	this.propertyValueTypeEnum = ParamValueType.STRING;
        }
        this.propertyValue1 = propertyValue1Str;
    }
    
    public ParamValueType getPropertyValueTypeEnum() {
        return propertyValueTypeEnum;
    }
    
    public void setPropertyValueTypeEnum(ParamValueType propertyValueType) {
        this.propertyValueTypeEnum = propertyValueType;
        this.propertyValueType = propertyValueType.toString();
        
        if (this.getPropertyValueTypeEnum().equals(ParamValueType.DATE)
        		&& this.getToCharFormat().isEmpty()){
        	setToCharFormat("yyyy-MM-dd");
        }
    }

    public String getPropertyValueType() {
        return propertyValueType;
    }

    public void setPropertyValueType(String propertyValueTypeString) {
        this.propertyValueType = propertyValueTypeString.toUpperCase();
        this.propertyValueTypeEnum = ParamValueType.valueOf(ParamValueType.class, propertyValueTypeString.toUpperCase());
        
        if (this.getPropertyValueTypeEnum().equals(ParamValueType.DATE)
        		&& this.getToCharFormat().isEmpty()){
        	setToCharFormat("yyyy-MM-dd");
        }
    }

    public OperatorType getOperator() {
        if (operator == null ){
            operator = OperatorType.EQ;
        }
        return operator;
    }
    public void setOperator(OperatorType operator) {
        this.operator = operator;
        this.operatorString = operator.toString();
    }

    @SuppressWarnings("unused")
    private String getOperatorString() {
        return this.operatorString;
    }
    
    @SuppressWarnings("unused")
    private void setOperatorString(String operatorString) {
        this.operatorString = operatorString;
        this.operator = OperatorType.valueOf(operatorString);
    }
    
    public List<PropertyFilter> getOrFilters() {
      if(orFilters==null){
          orFilters = new ArrayList<PropertyFilter>();
       }
        return orFilters;
    }
    
    public void setOrFilters(List<PropertyFilter> orFilters) {
        this.orFilters = orFilters;
    }

    /**用于限定可传入操作符的类型
     * 支持GT：大于
     * GE:大于等于
     * EQ:等于
     * LT:小于
     * LE：小于等于
     * LIKE:like 比较
     * BETWEEN:比较两个
     * NE：不等于
     * IS: 是
     * */ 
    public enum OperatorType {
        GT,GE,EQ,LT,LE,LIKE,NE,IS,BETWEEN,IS_NULL,IS_NOT_NULL,IS_EMPTY,IS_NOT_EMPTY,IN;
    }
   
    /**用于限定可传入参数值的类型*/
    public enum ParamValueType{
    INTEGER,STRING,LONG,DOUBLE,DATE,BOOLEAN,ARRAYLIST
    }
    
    public PropertyFilter(){
        
    }
    
    /**
     * 单一条件值构造函数，如：eq(等于)
     * 
     * @param propertyName
     * @param propertyValue
     * @param operator
     */
    public PropertyFilter(String propertyName, OperatorType operator, Object propertyValue) {
    
       // Assert.isTrue(!operator.equalsIgnoreCase("between"),
       // "使用between应该传入2个值！");
        //验证传入的值的类型
        setPropertyValueType(propertyValue.getClass().getSimpleName());// getName();
        try{
        	setPropertyValueTypeEnum(Enum.valueOf(ParamValueType.class, propertyValueType.toUpperCase()));
        }catch(RuntimeException e){
            throw new IllegalArgumentException(propertyName +"的类型不被接受！" , e);
        }
        this.propertyName = propertyName;
        this.propertyValue = propertyValue;
        this.propertyValue1 =null;
        this.operator = operator;
    }
    
     /**
     * 两个条件值的构造函数，如：between
     * @param propertyName
     * @param operator
     * @param propertyValue
     * @param propertyValue1
     */
    /*edit by zhangds 2010-10-28
     * 原因：propertyValueType 未能在构造函数中成功进行初始化
     * */
    public PropertyFilter(String propertyName, OperatorType operator, Object propertyValue,Object propertyValue1) {
        

        /*        String  propertyValueType = propertyValue.getClass().getSimpleName();
        String  propertyValueType1 = propertyValue.getClass().getSimpleName();
        try{
            Enum.valueOf(ParamValueType.class, propertyValueType.toUpperCase());
        }catch(RuntimeException e){
            throw new IllegalArgumentException("propertyName",e );
        }
        try{
            Enum.valueOf(ParamValueType.class, propertyValueType1.toUpperCase());
        }catch(RuntimeException e){
            throw new IllegalArgumentException("propertyName",e );
        }
*/   
        /*edit start */
        String   valueType = propertyValue.getClass().getSimpleName();
        String   valueType1 = propertyValue1.getClass().getSimpleName();
        Assert.isTrue(valueType.equals(valueType1),"属性值的类型应该相同");//两个属性值的类型应该相同
        setPropertyValueType(valueType);
        try{
        	setPropertyValueTypeEnum(Enum.valueOf(ParamValueType.class, valueType.toUpperCase()));
        }catch(RuntimeException e){
            throw new IllegalArgumentException("propertyName",e );
        }
        /*edit end */
        
        this.propertyName = propertyName;
        this.propertyValue = propertyValue;
        this.propertyValue1 =propertyValue1;
        this.operator = operator;
    }
    
    /**
     * 当不传入操作方法类型的情况下，默认操作为eq
     * @param propertyName
     * @param propertyValue
     * */
    public  PropertyFilter(String propertyName, Object propertyValue){
        this(propertyName, OperatorType.EQ, propertyValue);
    }
    
    public PropertyFilter or(List<PropertyFilter> orFilters){
        if(this.orFilters==null)this.orFilters =new ArrayList<PropertyFilter>();
        this.orFilters = orFilters;
        return this;
    }
    
    public PropertyFilter or(PropertyFilter orFilter){
        if(this.orFilters==null)this.orFilters =new ArrayList<PropertyFilter>();
        this.orFilters.add(orFilter);
        return this;
    }
    
    /**
     * 注意and 的条件中如果有相同的条件，将不会被计入，例如 (userName like ‘zhang’) and (userName like ‘li’) , (userName like ‘li’)将会被屏蔽掉
     * 
     */
    public PropertyFilter and(List<PropertyFilter> andFilters){
    	this.andFilters = andFilters;
    	return this;
    }
    
    /**
     * 注意and 的条件中如果有相同的条件，将不会被计入，例如 (userName like ‘zhang’) and (userName like ‘li’) , (userName like ‘li’)将会被屏蔽掉
     * 
     */
    public PropertyFilter and(PropertyFilter andFilter){
    	if (this.andFilters == null){
    		this.andFilters = new ArrayList<PropertyFilter>();
    	}
    	this.andFilters.clear();
    	this.andFilters.add(andFilter);
    	return this;
    }
}
